class Node {
  constructor(value, parentNode = null) {
    this.children = [];
    this.parent = parentNode;
    this.value = value;
  }

  addNode(value) {
    const segments = value.split("/");
    if (segments.length === 0) {
      return;
    }
    if (segments.length === 1) {
      const node = new Node(segments[0], this);
      this.children.push(node);
      return {
        node,
        index: this.children.length - 1,
      };
    }

    const existingChildNode = this.children.find(
      (child) => child.value === segments[0]
    );

    if (existingChildNode) {
      existingChildNode.addNode(segments.slice(1).join("/"));
    } else {
      const node = new Node(segments[0], this);
      node.addNode(segments.slice(1).join("/"));
      this.children.push(node);
      return {
        node,
        index: this.children.length - 1,
      };
    }
  }

  removeNode(value) {
    const segments = value.split("/");
    if (segments.length === 0) {
      return;
    }
    if (segments.length === 1) {
      const existingChilIndex = this.children.findIndex(
        (child) => child.value === segments[0]
      );

      if (existingChilIndex < 0) {
        throw new Error("Could not find matching value!");
      }

      this.children.splice(existingChilIndex, 1);
    }
    if (segments.length > 1) {
      const existingChildNode = this.children.find(
        (child) => child.value === segments[0]
      );
      if (!existingChildNode) {
        throw new Error(
          "Could not find matching path! Path segment: " + segments[0]
        );
      }
      existingChildNode.removeNode(segments.slice(1).join("/"));
    }
  }

  // （Depth-first）深度优先
  findNode_depth(value) {
    console.log("dir: ", this.value);
    for (const child of this.children) {
      if (child.value === value) {
        return child;
      }

      const nestedChildNode = child.findNode(value);
      if (nestedChildNode) {
        return nestedChildNode;
      }
    }
  }
  // （Breadth-first）广度优先
  findNode_breadth(value) {
    console.log("dir: ", this.value);
    for (const child of this.children) {
      if (child.value === value) {
        return child;
      }
    }
    for (const child of this.children) {
      const nestedChildNode = child.findNode(value);
      if (nestedChildNode) {
        return nestedChildNode;
      }
    }
  }

  findNode(value, pattern = "depth") {
    if (pattern === "depth") {
      return this.findNode_depth(value);
    } else {
      return this.findNode_breadth(value);
    }
  }
}

class Tree {
  constructor(rootValue) {
    this.root = new Node(rootValue);
  }

  add(path) {
    this.root.addNode(path);
  }

  remove(path) {
    this.root.removeNode(path);
  }

  find(value, pattern = "depth") {
    if (this.root.value === value) {
      return this.root;
    }

    return this.root.findNode(value, pattern);
  }
}

const filesystem = new Tree("/");
filesystem.add("documents/profile/message.txt");
filesystem.add("games/a.exe");
filesystem.add("profiles");
filesystem.add("games/b.exe");
filesystem.remove("games/a.exe");
// filesystem.remove("gamesxx/a.exe");
// filesystem.remove("games/axx.exe");
console.log(filesystem);

console.log(filesystem.find("profile"));
console.log("-".repeat(50));
console.log(filesystem.find("profiles"));
console.log("-".repeat(50));
console.log(filesystem.find("b.exe"));

/*
class Node {
  constructor(value, parentNode = null) {
    this.children = [];
    this.parent = parentNode;
    this.value = value;
  }

  addNode(value) {
    const node = new Node(value, this);
    this.children.push(node);
    return {
      node,
      index: this.children.length - 1,
    };
  }

  removeNode(index) {
    this.children.splice(index, 1);
  }
}

class Tree {
  constructor(rootValue) {
    this.root = new Node(rootValue);
  }
 }

const filesystem = new Tree("/");

const documentsNodeData = filesystem.root.addNode("/documents");
documentsNodeData.node.addNode("code.exe");
documentsNodeData.node.addNode("a.txt");

const videosNodeData = filesystem.root.addNode("/videos");
videosNodeData.node.addNode("1.mp4");

console.log(filesystem);
*/
